package hn.sigit.logic.viewer.toolbox;

import hn.sigit.dao.hnd.administrative.HND_PropertyDAO;
import hn.sigit.dao.hnd.cadastre.HND_ParcelDAO;
import hn.sigit.dao.hnd.ladmshadow.ParcelDAO;
import hn.sigit.dao.hnd.ladmshadow.PropertyDAO;
import hn.sigit.logic.geometry.GeometryOperations;
import hn.sigit.logic.geometry.MergeException;
import hn.sigit.logic.ladm.RightsUtil;
import hn.sigit.logic.viewer.InteractiveViewerHelper;
import hn.sigit.model.commons.IParcel;
import hn.sigit.model.commons.IProperty;
import hn.sigit.model.hnd.administrative.HND_Property;
import hn.sigit.model.hnd.cadastre.HND_Parcel;
import hn.sigit.model.hnd.ladmshadow.Parcel;
import hn.sigit.model.hnd.ladmshadow.Property;
import hn.sigit.util.NoEqualRightsException;

import java.io.Serializable;
import java.util.Date;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;

import com.vividsolutions.jts.geom.Polygon;

public class MergeHelper implements Serializable {
	private static final long serialVersionUID = 1L;

	private InteractiveViewerHelper interactiveViewerHelper;
	
	private Long parcelToMergeId1;
	private Long parcelToMergeId2;
	private ViewerCallable viewerCallable;
	
	public MergeHelper(InteractiveViewerHelper interactiveViewerHelper) {
		this.interactiveViewerHelper = interactiveViewerHelper;
	}
	
	private void doMerge() throws MergeException, NoEqualRightsException {
		if (parcelToMergeId1 == null || parcelToMergeId2 == null)
			throw new IllegalArgumentException("dataentry.merge.error_parcels_not_selected");
		
		IParcel parcel1 = null;
		IParcel parcel2 = null;
		if (interactiveViewerHelper.getPresentationId() == null) {
			//we are assuming that if there is not presentation active, then
			//we work with the front-end schema
			parcel1 = HND_ParcelDAO.loadParcelById(parcelToMergeId1);
			parcel2 = HND_ParcelDAO.loadParcelById(parcelToMergeId2);
		}
		else {
			parcel1 = ParcelDAO.loadParcelById(parcelToMergeId1);
			parcel2 = ParcelDAO.loadParcelById(parcelToMergeId2);
		}
		
		if (parcel1 == null || parcel2 == null)
			throw new IllegalArgumentException("One of both parcels not found");
		
		IProperty property1 = parcel1.getProperty();
		IProperty property2 = parcel2.getProperty();
		
		if (RightsUtil.propertyRightsEqual(property1, property2)) {
			Polygon shape1 = parcel1.getShape();
			Polygon shape2 = parcel2.getShape();
			
			Date timeStamp = new Date();

			Polygon newShape = GeometryOperations.mergePolygons(shape1, shape2);

			IParcel newParcel = parcel1.clone();
			newParcel.setBeginLifespanVersion(timeStamp);
			newParcel.setEndLifespanVersion(null);
			newParcel.setShape(newShape);
			newParcel.setFieldTab(interactiveViewerHelper.getFieldTabCounter());
			if (newParcel instanceof Parcel) {
				((Parcel) newParcel).setModified(false);
				((Parcel) newParcel).setOriginal(false);
			}
			
			IProperty newProperty = parcel1.getProperty().clone();
			newProperty.setBeginLifespanVersion(timeStamp);
			newProperty.setEndLifespanVersion(null);
			newProperty.getSpatialUnits().clear();
			newProperty.getSpatialUnits().add(newParcel);
			if (newProperty instanceof Property) {
				((Property) newProperty).setModified(false);
				((Property) newProperty).setOriginal(false);
			}

			newParcel.getBaunits().clear();
			newParcel.getBaunits().add(newProperty);

			if (parcel1 instanceof Parcel)
				((Parcel) parcel1).setModified(true);
			parcel1.setEndLifespanVersion(timeStamp);
			property1.setEndLifespanVersion(timeStamp);
			
			if (parcel2 instanceof Parcel)
				((Parcel) parcel2).setModified(true);
			parcel2.setEndLifespanVersion(timeStamp);
			property2.setEndLifespanVersion(timeStamp);

			if (parcel1 instanceof Parcel) {
				ParcelDAO.save(parcel1);
				ParcelDAO.save(parcel2);
				ParcelDAO.save(newParcel);
			}
			else if (parcel1 instanceof HND_Parcel) {
				HND_ParcelDAO.save(parcel1);
				HND_ParcelDAO.save(parcel2);
				HND_ParcelDAO.save(newParcel);
			}
			
			if (property1 instanceof Property) {
				PropertyDAO.save(property1);
				PropertyDAO.save(property2);
				PropertyDAO.save(newProperty);
			}
			else if (property1 instanceof HND_Property) {
				HND_PropertyDAO.save(property1);
				HND_PropertyDAO.save(property2);
				HND_PropertyDAO.save(newProperty);
			}
			
			interactiveViewerHelper.setSelectedZone(newParcel);
			
			
			setParcelToMergeId1(null);
			setParcelToMergeId2(null);

			if (viewerCallable != null)
				viewerCallable.afterMerge(parcel1, property1, parcel2, property2, newShape, timeStamp);
		}
		else
			throw new NoEqualRightsException("dataentry.merge.error_noequal_rights");
	}

	public String applyMerge() {
		try {
			doMerge();
		}
		catch (MergeException me) {
			FacesContext.getCurrentInstance().addMessage("",
					new FacesMessage(FacesMessage.SEVERITY_ERROR,
							interactiveViewerHelper.getResBundle().loadMessage(me.getExceptionBundle()) + ": ",
							interactiveViewerHelper.getResBundle().loadMessage(me.getMessage())));
		}
		catch (NoEqualRightsException nere) {
			FacesContext.getCurrentInstance().addMessage("",
					new FacesMessage(FacesMessage.SEVERITY_ERROR,
							interactiveViewerHelper.getResBundle().loadMessage(nere.getExceptionBundle()) + ": ",
							interactiveViewerHelper.getResBundle().loadMessage(nere.getMessage())));
		}
		catch (IllegalArgumentException e) {
			FacesContext.getCurrentInstance().addMessage("",
					new FacesMessage(FacesMessage.SEVERITY_ERROR,
							interactiveViewerHelper.getResBundle().loadMessage(e.getMessage()) + ": ",
							interactiveViewerHelper.getResBundle().loadMessage(e.getMessage())));
		}
			
		return null;
	}
	
	public Long getParcelToMergeId1() {
		return parcelToMergeId1;
	}
	public void setParcelToMergeId1(Long parcelToMergeId1) {
		this.parcelToMergeId1 = parcelToMergeId1;
	}

	public Long getParcelToMergeId2() {
		return parcelToMergeId2;
	}
	public void setParcelToMergeId2(Long parcelToMergeId2) {
		this.parcelToMergeId2 = parcelToMergeId2;
	}

	public ViewerCallable getViewerCallable() {
		return viewerCallable;
	}
	public void setViewerCallable(ViewerCallable viewerCallable) {
		this.viewerCallable = viewerCallable;
	}
}
